// Shorthand
if (typeof(Cc) == "undefined")
  var Cc = Components.classes;
if (typeof(Ci) == "undefined")
  var Ci = Components.interfaces;
if (typeof(Cu) == "undefined")
  var Cu = Components.utils;
if (typeof(Cr) == "undefined")
  var Cr = Components.results;

Cu.import('resource://gre/modules/XPCOMUtils.jsm');

// Make a namespace.
if (typeof Focustrack == 'undefined') {
  var Focustrack = {};
}

/**
 * UI controller that is loaded into the main player window
 */
Focustrack.Controller = {
  // Debug variables
  DEBUG : false,
  className: "FocusTrack",
  _consoleService: null,

  _mediaCoreManager: null,
  _isEnabled: false,
  _notifyTimer: null,
  
  /**
   * Internal debugging functions
   */
  /**
   * \brief Dumps out a message if the DEBUG flag is enabled with
   *        the className pre-appended.
   * \param message String to print out.
   */
  _debug: function (message)
  {
    if (!this.DEBUG) return;
    try {
      dump(this.className + ": " + message + "\n");
      this._consoleService.logStringMessage(this.className + ": " + message);
    } catch (err) {
      // We do not want to throw an exception here
    }
  },
  
  /**
   * \brief Dumps out an error message with the className + ": [ERROR]"
   *        pre-appended, and will report the error so it will appear in the
   *        error console.
   * \param message String to print out.
   */
  _logError: function (message)
  {
    try {
      dump(this.className + ": [ERROR] - " + message + "\n");
      Cu.reportError(this.className + ": [ERROR] - " + message);
    } catch (err) {
      // We do not want to thow an exception here
    }
  },
  
  toggleFocusTrack: function () {
    SBDataSetIntValue("focustrack.enabled",
                      (SBDataGetIntValue( "focustrack.enabled" ) + 1) % 2 );
    this._isEnabled = (SBDataGetIntValue( "focustrack.enabled" ) == 1);
    this.UpdateIcon();
  },

  UpdateIcon: function () {
    var ftIcon = document.getElementById('focusTrackIcon');
    if (this._isEnabled) {
      ftIcon.setAttribute("src", "chrome://focustrack/skin/EnabledEye-16.png");
    } else {
      ftIcon.setAttribute("src", "chrome://focustrack/skin/DisabledEye-16.png");
    }
  },
  
  DisplayIcon: function(aShouldHide) {
    var ftIcon = document.getElementById('focusTrackIcon');
    if (aShouldHide) {
      ftIcon.setAttribute("hidden", true);
    } else {
      ftIcon.removeAttribute("hidden");
    }
  },

  observe: function(aSubject, aTopic, aData) {
    this.DisplayIcon((aData == 0));
  },

  /**
   * Called when the window finishes loading
   */
  onLoad: function() {
    // Make sure we have the javascript modules we're going to use
    if (!window.SBProperties) 
      Cu.import("resource://app/jsmodules/sbProperties.jsm");
    if (!window.LibraryUtils) 
      Cu.import("resource://app/jsmodules/sbLibraryUtils.jsm");

    this.DEBUG = Application.prefs.getValue("songbird.focustrack.debug", false);
    if (this.DEBUG) {
      this._consoleService = Cc["@mozilla.org/consoleservice;1"]
                              .getService(Ci.nsIConsoleService);
    }
    this._debug("Starting Focus Track");

    this._isEnabled = (SBDataGetIntValue( "focustrack.enabled" ) == 1);
    this.DisplayIcon((SBDataGetIntValue( "focustrack.statusbar_icon_enabled" ) == 0));
    this.UpdateIcon();

    var createDataRemote =  new Components.Constructor(
                                "@songbirdnest.com/Songbird/DataRemote;1",
                                Ci.sbIDataRemote,
                                "init");
    metadataImage = createDataRemote("focustrack.statusbar_icon_enabled", null);
    metadataImage.bindObserver(this, true);

    this._notifyTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);

    // Load the mediaCoreManager since dataremotes are too slow to
    // update the album art.
    this._mediacoreManager = Cc["@songbirdnest.com/Songbird/Mediacore/Manager;1"]
                               .getService(Ci.sbIMediacoreManager);
    this._mediacoreManager.addListener(this);
  },
  
  /**
   * Called when the window is about to close
   */
  onUnLoad: function() {
    this._mediacoreManager.removeListener(this);
    this._mediacoreManager = null;
    this._notifyTimer = null;
  },

  /**
   * Get the current active browser window if there is one.
   */
  getBrowser: function() {
    var retval = null;
    try {
      // Dig through the parent chain to find a happy gBrowser.
      for ( var win = window; 
            win != null && win != win.parent && 
            typeof win.gBrowser == 'undefined'; 
            win = win.parent ) ; // Yes, it is there on purpose.
      if ( win ) {
        retval = win.gBrowser;
      }
    } catch(e) {}
    return retval;
  },
  
  /**
   * Show the current track
   */
  onCurrentTrack: function() {
    if (!this._isEnabled) {
      return;
    }
    
    this._debug("onCurrentTrack");
    if (!this._mediacoreManager.sequencer.view) {
      // nothing to see here, move along
      this._debug("No playingView");
      return;
    }

    // Find a gBrowser in the window hierarchy chain (for display panels, etc)
    var browser = this.getBrowser();
    if (typeof browser == 'undefined') {
      // where do you expect me to show you this currently playing
      // track of yours?
      this._debug("No Browser");
      return;
    }
    
    /*
     * I have to do this all here instead of calling browser.showIndexInView
     * because that function will switch to the tab that this media view is
     * located on which we do not want to do because then we will interrupt the
     * user. But we still want to highlight the track so that when they do
     * switch back it will be highlighted correctly.
     */
    if (this._mediacoreManager.sequencer.viewPosition >= 0) {
      var mediaView = this._mediacoreManager.sequencer.view;
      var trackIndex = this._mediacoreManager.sequencer.viewPosition;
      var mediaTab = browser.getTabForView(mediaView);
      if (mediaTab) {
        if (mediaTab.mediaPage) {
          mediaTab.mediaPage.highlightItem(trackIndex);
        } else if (mediaTab.outerPlaylist) {
          var tree = mediaTab.outerPlaylist.tree;
          tree.treeBoxObject.ensureRowIsVisible(trackIndex);
          tree.view.selection.select(trackIndex);
        }
      }
    }
  },
  
  /*********************************
   * sbIMediacoreEventListener and Event Handlers
   ********************************/
  onMediacoreEvent: function AlbumArt_onMediacoreEvent(aEvent) {
    switch(aEvent.type) {
      case Ci.sbIMediacoreEvent.TRACK_CHANGE:
        this._debug("TRACK_CHANGE");
        this._notifyTimer.cancel();
        this._notifyTimer.initWithCallback(this,
                                           500,
                                           Ci.nsITimer.TYPE_ONE_SHOT);
      break;
    }
  },

  /*********************************
   * nsITimerCallback
   ********************************/
  notify: function(aTimer) {
    this.onCurrentTrack();
  },

  /*********************************
   * nsISupports
   ********************************/
  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback,
                                         Ci.sbIMediacoreEventListener])
  
};

window.addEventListener("load",
                        function(e) { Focustrack.Controller.onLoad(e); },
                        false);
window.addEventListener("unload",
                        function(e) { Focustrack.Controller.onUnLoad(e); },
                        false);
